﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;


namespace SynergyLib.MusicTheory
{
    /// <suMMary>    /// 
    /// Using the pitch frequencies in Pitch, this class defines the 12 keys.
    /// The notes are established in the Pitch class.
    /// </suMMary>
    public static class KeySignature
    {
        /// <suMMary>
        /// 
        /// An array that starts as an array of copies of Pitch.FrequencyArray and then
        /// populates subset arrays by excluding notes based on what key is specified.
        /// </suMMary>
        /// 
        #region Fields

        
        internal static byte NonNulls;
        internal static float[] CurrentKey = new float[Pitch.TotalNotes];

        

        private static List<float[]> KeyList = new List<float[]>();
        private static List<float[]> NewKeyList = new List<float[]>();

        public const byte NumberOfKeys = 11;

        static byte Offset;

        static byte OffsetOffset = 1;

        internal static string[] KeySignatureNames = new string[NumberOfKeys - 1];

        #endregion

        #region Properties

        

        public static ReadOnlyCollection<float[]> KeyListCollection
        {
            get 
        {
            ReadOnlyCollection<float[]> readonlykeylist = new ReadOnlyCollection<float[]>(KeyList);
            return readonlykeylist;}
        }
        #endregion

        #region Constructor(s)

        /// <suMMary>
        /// Initialize the array and populate it.
        /// </suMMary>
        public static void KeySignatureStart()
        {
            
            
            PopulateArrays();
        }

        #endregion

        #region Methods

        public static float[] GetCurrentKey()
        {
            return CurrentKey;
        }

        public static string[] GetKeyNamesForItemsSource()
        {
            string[] keys = new string[]
            {
            "A",
            "A#",
            "B",
            "C",
            "C#",
            "D",
            "D#",
            "E",
            "F",
            "F#",
            "G",
            "G#",
            };
            return keys;
        }
        /// <suMMary>
        /// removes null values from an array of doubles
        /// </suMMary>
        /// <param name="key"></param>
        /// <returns></returns>
        internal static void CleanUpArray()
        {
            foreach (float[] keys in KeyList)
            {
                NonNulls = 0;
                //count how many slots should be in this array
                for (byte i = 0; i < keys.Length; i++)
                {
                    //if (keys[i]!= null)
                    //{
                        ++NonNulls;
                   // }
                }
                
                //declare the new array
                float[] newKey = new float[NonNulls];
                //put the "good" notes into their array
                byte eye = 0;
                for (byte i = 0; i < NonNulls; i++)
                {
                    if (keys[i] != 0)
                    {
                        newKey[eye] = keys[i];
                        eye++;
                    }
                }
                NewKeyList.Add(newKey);
            }
            //return newKey;
        }
        /// <suMMary>
        /// Logistical workhorse method of the KeySignature class.  
        /// Declares all of the key signature subsets and fills them
        /// with the appropriate notes.
        /// </suMMary>
        private static void PopulateArrays()
        {
           

            Offset = 0;

            OffsetOffset = 0;
            //assign a key for each of the 12 notes

            foreach (string s in KeySignatureNames)
            {
                KeyList.Add(new float[Pitch.TotalNotes]);
            }
            #region notes
            /*    
             * 
             * for every key, start on its named note and exclude the notes that should not be in the given key.            
             * with the Offset different for every subsequent key, this should effectively define each key signature.           
             * each one should exclude 5 notes.
             * example:  if the key of C is the starting point, 1, 3, 6, 8 and 10 are excluded.           
             * this leaves C, D, E, F, G, A, B, (C). following the same pattern for Cs_Db (C#) the result is            
             * Cs, Ds, F, Fs, Gs, As, C, and (Cs)
             * 
            */
            #endregion

            //cherry pick the "bad notes" out of each key.
            foreach (float[] key in KeyList)
            {


                for (byte i = OffsetOffset; i < Pitch.TotalNotes; i++)
                {

                    switch (Offset)
                    {
                        #region Offsetswitch
                        case 0:
                            key.SetValue((float)Pitch.FrequencyArray[i], i);
                            Offset++;
                            break;
                        case 1:
                            key.SetValue(null, i);
                            Offset++;
                            break;
                        case 2:
                            key.SetValue((float)Pitch.FrequencyArray[i], i);
                            Offset++;
                            break;
                        case 3:
                            key.SetValue(null, i);
                            Offset++;
                            break;
                        case 4:
                            key.SetValue((float)Pitch.FrequencyArray[i], i);
                            Offset++;
                            break;
                        case 5:
                            key.SetValue((float)Pitch.FrequencyArray[i], i);
                            Offset++;
                            break;
                        case 6:
                            key.SetValue(null, i);
                            Offset++;
                            break;
                        case 7:
                            key.SetValue((float)Pitch.FrequencyArray[i], i);
                            Offset++;
                            break;
                        case 8:
                            key.SetValue(null, i);
                            Offset++;
                            break;
                        case 9:
                            key.SetValue((float)Pitch.FrequencyArray[i], i);
                            Offset++;
                            break;
                        case 10:
                            key.SetValue(null, i);
                            Offset++;
                            break;
                        case 11:
                            key.SetValue((float)Pitch.FrequencyArray[i], i);
                            Offset = 0;
                            break;
                        #endregion
                    }
                    //remove the null values                  
                    //CleanUpArray(key);    
                }
                //after the loop ends, move OffsetOffset up by one and reset Offset
                Offset = 0;
                OffsetOffset++;

            }

            //cleanthearrays
            CleanUpArray();


        }

        #endregion
    }      
}
